#include <iostream>
#include <memory>
#include <functional>

class MermoryPool{
        private:
            static consteexpr size_t kBlockSize = 4096;  //size_t常用于表达对象的大小
            //和内存中的字节数
            struct MermoryBlock{
                MermoryBlock* next;
                char data[0];  //这里是一个柔性数组，他最大的作用是使得结构体在分配内存时
            }；   //本身不占用结构体的空间，仅作为一个标识，指示数据从结构体末尾开始存储     
            
            MermoryBlock* freeList = nullptr;

        public:
            void* Allocate(size_t size){
                size = (size + size(void*) - 1) & ~(sizeof(void*) -1);//内存对齐
                //这段确保分配的内存大小是sizeof(void*)的倍数，不太了解

                if(!freeList){//如果没内存就申请，有点像链表感觉
                    //扩展内存池
                    char* newBlock = new char[kBlockSize];
                    freeList = reinterpret_cast<MeroryBlock*>(newBlock);
                    //reinterpret_cast 是一种强制类型转换运算符
                    //这里就是将新生成的强转一下
                    freeList->next = nullptr;
                }

                void* ptr = freeList;
                freeList = freeList->next;
                return ptr;
            }
            
            //模拟释放内存
            void Deallocate(void* ptr){
                MermoryBlock* block = reinterpret_cast<MermoryBlock*>(ptr);  //将指针强转为该类对应的在进行后续处理
                block->next = freeList;
                freeList = block; 
            }

            ~MermoryPool(){
                while(freeList){
                    MermoryBlock* next = freeList->next;
                    delete[] reinterpret_cast<char*>(freeList);
                    freeList = next;
                }
            }           
};


//这里来定义一个删除器
template <typename T>
struct PoolDeleter{
    MermoryPool& pool;

    explicit PoolDeleter(MermoryPool& p) : pool(p){}

    void operator()(T* ptr){
        ptr->~T();
        //显式析构调用
        pool.Deallocate(ptr);   //这里将内存归还池中
    }
};

//内存池智能指针
template<typename T>
using PoolPtr = std::unique_ptr<T,PoolDelete<T>>;

//创建一个对象的模板 
template<typename T,typename... Args>
PoolPtr<T> MakePoolObject(MermoryPool& pool,Args&&... args){
    void* mem = pool.Allocate(sizeof(T));
    return PoolPtr<T>(
        new(mem) T(std::forward<Args>(args)...),

        PoolDelete<T> (pool)
    );
}


//测试用例类
class TestObject{
    public:
        int id;
        explicit TestObject(int i) : id(i){
            std::cout<<"构造对象#"<<id<<std::endl;
        }

        ~TextObject(){
            std::cout<<"析构对象"<<id<<std::endl;
        }
};

int main(){
    MermoryPool pool;

    {
        auto obj1 = MakePoolObject<TextObject>(pool,1);
        auto obj2 = MakePoolObject<TextObject>(pool,2); //auto非常地好用

        std::cout<<"对象1 id:"<<obj1->id<<std::endl;
        std::cout<<"对象2 id:"<<obj2->id<<std::endl;

        //这里测试数组
        auto arr = MakePoolObject<int[]>(pool,3);

        arr.get()[0] = 10;
        arr.get()[1] = 20;
        std::cout << "数组值: " << arr[0] << "," << arr[1] << std::endl;
    } // zheli自动触发内存回收
    
        std::cout << "----- 作用域外 -----" << std::endl;
    
    // 重用内存测试
    auto obj3 = MakePoolObject<TestObject>(pool, 3);
    std::cout << "新对象地址: " << obj3.get() << std::endl;
    
    return 0;
    }
}